#pragma once 
#include<iostream>
#include<string>
#include<unistd.h>
#include<cstdlib>
#include<sys/types.h>
#include<sys/socket.h>
#include<cerrno>
#include<string.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<functional>
using namespace std;

namespace Server{
   static const string defaultIp="0.0.0.0";//自定义ip
   enum{USAGE_ERR=1,SOCKET_ERR=2,BIND_ERR,OPEN_ERR};
   static const int NUM=1024;
   using func_t =function<void(int,string,uint16_t,string)>;
class udpServer
{ 
public:
  udpServer(func_t func,const uint16_t &port,const string ip=defaultIp):func(func),_port(port),_ip(ip),_sockfd(-1)
  {}
  void initServer()
  {  //1.创建套接字 socket
     //2.创建网络套接字的结构体  struct sockaddr_in ，然后对结构体初始化（bzero），填充
     //3.将套接字绑定上ip和端口号 bind
     _sockfd=socket(AF_INET,SOCK_DGRAM,0);
     if(_sockfd==-1)
     {
      cerr<<"socket error:"<<errno<<" : "<<strerror(errno)<<endl;
      exit(SOCKET_ERR);
     } 
     cout << "socket success: " << " : " << _sockfd << endl;
     struct sockaddr_in local;
     bzero(&local,sizeof(local));//初始化local，全部变为0
     local.sin_family=AF_INET;//设置首两个字节决定它的套接字类型
     local.sin_port=htons(_port);//端口号的转入
     local.sin_addr.s_addr=inet_addr(_ip.c_str());//将点分十进制转化为整型，以及本地转网络，这个ip用0.0.0.0是为了便于用于各种对这个服务器并且对应port发更加方便。
     int n=bind(_sockfd,(struct sockaddr*)&local,sizeof(local));//将网络套接字与网络文件的结构体绑定
     if(n==-1)
     {
       cerr<<"bind error:"<<errno<<":"<<strerror(errno)<<endl;
       exit(BIND_ERR);
     }
  }
  void start()
  {
   //服务器的本质就是个死循环，操作系统就是死循环
   char buffer[NUM];//用于接收客户端发的信息
   for(;;)
   { //因此不能有内存泄露
     //1.创建客户端的结构体（输出型参数，辨别那一个客户端发的数据）
     //2.读客户端发的数据：数据是什么，谁发出的
     struct sockaddr_in peer;//创建结构体用来获取客户端信息
     socklen_t len=sizeof(peer);
     ssize_t s=recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);//获取客户端发的消息
     if(s>0)
     { buffer[s]=0;
      string clientip=inet_ntoa(peer.sin_addr);//1.网络序列 2.int->点分十进制IP,获取客户端的ip
      uint16_t clientport=ntohs(peer.sin_port);//获取端口号
      string message = buffer;

       cout << clientip <<"[" << clientport << "]# " << message << endl;
       func(_sockfd,clientip,clientport,message);
     }


   }

  }
  ~udpServer()
  {
    
  }
private:
  uint16_t _port;
  string _ip;//点分十进制的IP-字符串，可读性好，uint32_t ip:整数风格的IP-网络通信使用
  int _sockfd;//套接字的描述符类似于文件描述符
  func_t func;
  
};
}